/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: ws
 * Date: 2023-12-24
 * Time: 15:38
 */



// 生产者消费者模型

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 传统写法
 * 题目:一个初始值为零的变量，两个线程对其交替操作，一个加1一个减1﹐来轮
 *
 *
 * 1. 线程操作资源类
 * 2. 判断，干活，通知
 * 3. 防止虚假唤醒机制
 *    即：多线程的判断需要用 while，不能使用 if（jdk 要求的，保证线程不会出错）
 */
public class T4 {
    public static void main(String[] args) throws InterruptedException {

        // 传统

//        ShareData shareData = new ShareData();
//
//        new Thread(() -> {
//            for (int i = 1; i <= 5; i++) {
//                try {
//                    shareData.increment();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }, "Produce0").start();
//
//
//        new Thread(() -> {
//            for (int i = 1; i <= 5; i++) {
//                shareData.decrement();
//            }
//        }, "Consume0").start();
//
//
//        // 多个线程验证性质 3
//        // 发现不是生产一个就消费一个了
//        new Thread(() -> {
//            for (int i = 1; i <= 5; i++) {
//                try {
//                    shareData.increment();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }, "Produce1").start();
//
//
//        new Thread(() -> {
//            for (int i = 1; i <= 5; i++) {
//                shareData.decrement();
//            }
//        }, "Consume2").start();





        // 维新

        MyResource myResource = new MyResource(new ArrayBlockingQueue<>(10));
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t生产线程启动");
            try {
                myResource.myProd();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "Prod").start();

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t消费线程启动");
            try {
                myResource.myConsumer();
                System.out.println();
                System.out.println();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "Consumer").start();


        Thread.sleep(5000);

        System.out.println();

        System.out.println("时间到，main 线程叫停");
        myResource.stop();
    }
}


class MyResource {
    // 默认开启
    private volatile boolean FLAG = true;
    private final AtomicInteger atomicInteger = new AtomicInteger();

    BlockingQueue<String> blockingQueue = null;

    public MyResource(BlockingQueue<String> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    public void myProd() throws InterruptedException {
        String date = null;
        boolean retValue;
        while (FLAG) {
            date = atomicInteger.incrementAndGet() + "";
           retValue =  blockingQueue.offer(date, 2L, TimeUnit.SECONDS);
            if (retValue) {
                System.out.println(Thread.currentThread().getName() + "\t插入队列" + date + "成功");
            } else {
                System.out.println(Thread.currentThread().getName() + "\t插入队列" + date + "失败");
            }
            // 一秒生产一个
            TimeUnit.SECONDS.sleep(1);
        }
        System.out.println(Thread.currentThread().getName() + "\t停止生产");
    }

    public void myConsumer() throws InterruptedException {
        String result = null;
        while (FLAG) {
            result = blockingQueue.poll(2L, TimeUnit.SECONDS);
            if (result == null || result.equalsIgnoreCase("")) {
                FLAG = false;
                System.out.println(Thread.currentThread().getName() + "\t超过两秒没有取到，退出");
                System.out.println();
                System.out.println();
                return;
            }

            System.out.println(Thread.currentThread().getName() + "\t消费队列" + result + "成功");

        }
    }

    public void stop() {
        this.FLAG = false;
    }



}



class ShareData {// 资源类

    private int number = 0;
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    public void increment() throws InterruptedException {
        lock.lock();

        try {
            // 1. 判断
//            if (number != 0) {
            while (number != 0) {
                // 有值，等待消费，不能生产
                condition.await();
            }
            // 2. 干活
            number++;
            System.out.println(Thread.currentThread().getName() + "\t" + number);
            // 3. 通知，唤醒
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void decrement() {
        lock.lock();
        try {
            // 1. 判断
//            if (number == 0) {
            while (number == 0) {
                // 有值，等待消费，不能生产
                condition.await();
            }
            // 2. 干活
            number--;
            System.out.println(Thread.currentThread().getName() + "\t" + number);
            // 3. 通知，唤醒
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}